parser grammar AnalizadorParser;

options {
  language = Java;
  tokenVocab = AnalizadorLexer;
  backtrack = true;
}

@header {
  package practpl.ocho;
  import java.util.Hashtable;
}

@members {

  Hashtable variables = new Hashtable();
  int tab = 0;
  
  String tabulador(int tab) {
    String aux = "";
    for (int i = 0; i < tab; i++) {
      aux += " ";
    }
    return aux;
  }
  
    private ArrayList<RecognitionException> errors = new ArrayList<RecognitionException>();
    public ArrayList<RecognitionException> getErrors() {
       return errors;
    }
    @Override
    public void reportError (RecognitionException e) {
       String msg = getErrorMessage(e, getTokenNames());
       System.err.println(msg);
       errors.add(e);
    }   
  
}


//CALCULADORA SIMPLE

entrada: (instruccion)*;

instruccion
: e=expr SEPARADOR {System.out.println("Expresion: "+e);}
| v=asignacion SEPARADOR {System.out.println("Asignacion("+ v + ") => " + variables.get(v));}
;

expr returns [int res=0]
: e1=exp_mult {res=e1;}
((MAS e2=exp_mult {res=res+e2;})
|(MENOS e2=exp_mult {res=res-e2;}))*
;

exp_mult returns [int res=0]
: e1=exp_base {res=e1;}
((MULT e2=exp_base {res=res*e2;})
|(DIV e2=exp_base {res = res/e2;}))*;
  catch [ArithmeticException ae] {
    System.err.println("División por CERO");
    throw ae;
  }

exp_base returns [int res=0]
: n=NUMERO {res = new Integer(n.getText()).intValue();}
| IDENT 
    {
			Integer v = (Integer)variables.get($IDENT.text);
			if ( v!=null ) $res = v.intValue();
			else { {variables.put($IDENT.text, new Integer(0));}
			  $res = (Integer)variables.get($IDENT.text);
			}
    }
| PARENTA e=expr PARENTC
{res = e;}
;

asignacion returns [String variable=""]
: i=IDENT ASIGNA e=expr {variable = $i.text;}
{variables.put($i.text, new Integer(e));}
;


//CODIGO C

codigoc
: ((buclewhile [0]) 
| (sentenciaif [0]))+;

buclewhile [int nbw]
: WHILE {nbw++;} PARENTA condicion PARENTC bloque[nbw] {nbw--;};

condicion: IDENT;

bloque[int nbw]
: LLAVEA ((sentenciaif [nbw]) 
| (BREAK SEPARADOR {if (nbw > 0)
                      System.out.println("El Break está dentro de un bucle while");
                    else 
                      System.out.println("El Break NO está dentro de un bucle while"); 
                    } ))+ LLAVEC;
                      
                   
sentenciaif [int nbw]
: IF PARENTA condicion PARENTC bloque[nbw];


//XML

elementos : (elemento)*
;

elemento : (MENOR a=IDENT MAYOR elementos MENOR DIV c=IDENT MAYOR)
{
  if ($a.text.equals($c.text)) {
    System.out.println("Las etiquetas coinciden");
  }
  else {
    System.out.println("Las etiquetas NO coinciden");
  }
}
| TEXTO
;

//FORMATEO

formateo [String s]: v=tipodedato id=IDENT pa=PARENTA td=tipodedato pac=PARENTC sb=bloque2
          {s += $v.text; s += " "; s += $id.text; s += " "; s += $pa.text; s += $td.text; s += $pac.text; s += sb;
          System.out.println(s);};
          
bloque2 returns [String sbloque=""]: lla=LLAVEA {sbloque += " ";
                                                 sbloque += $lla.text;
                                                 tab += 3;
                                                 sbloque += "\n";} ( (sal=asignacion2 | sal=declaracion | sal=sentenciaif2 | sal=funcion) {
                                                 sbloque += tabulador(tab);
                                                 sbloque += sal; sbloque += "\n";} )+ llc=LLAVEC {tab-= 3;
                                                                                                  sbloque += tabulador(tab);
                                                                                                  sbloque += $llc.text;};
                              

declaracion returns [String sdecl=""]: td=tipodedato id=IDENT {sdecl += $td.text; 
                                                               sdecl += " "; 
                                                               sdecl += $id.text;} (c=COMA id2=IDENT {sdecl += $c.text;
                                                                                                       sdecl += " ";
                                                                                                       sdecl += $id2.text;})* sep=SEPARADOR {sdecl += $sep.text;};
                                        
                                    
asignacion2 returns [String sasig=""]: id=IDENT ig=IGUAL (in=IDENT|in=NUMERO {sasig += $in.text;}) { sasig += $id.text;
												                                                                             sasig += " ";
												                                                                             sasig += $ig.text;
												                                                                             sasig += " ";
												                                                                             sasig += $in.text; } ((o=operadores in2=(IDENT|NUMERO) {sasig += $o.text;
												                                                                                                                                     sasig += $in2.text;} ) )* sep=SEPARADOR {sasig += $sep.text;};
sentenciaif2 returns [String sif=""]: i=IF pa=PARENTA s=condicion2 pc=PARENTC sb=bloque2 {sif += $i.text;
                                                                                         sif += $pa.text;
                                                                                         sif += s;
                                                                                         sif += $pc.text;
                                                                                         sif += sb;};
                                                                                          
funcion returns [String sfun=""]: id=IDENT pa=PARENTA {sfun += $id.text;
                                                       sfun += $pa.text;} ( (s=TEXTO|s=COMA|s=IDENT) {sfun += $s.text;} )* pc=PARENTC sep=SEPARADOR {sfun += $pc.text;
                                                                                                                                                     sfun += $sep.text;};
                                                       


tipodedato: (INT | VOID);
operadores: (MAS | MENOS | DIV | MULT);
comparadores: (MAYORIGUAL | MENORIGUAL | COMPARA | DISTINTO | MAS | MENOS);

condicion2 returns [String scond=""]: ni=(NUMERO|IDENT) {scond += $ni.text;} o=operadores {scond += $o.text;} ni2=(NUMERO|IDENT) {scond += $ni2.text;} c=comparadores ni=(NUMERO|IDENT) {scond += $c.text;
                                                                                                                                                                                         scond += $ni.text;};
